#! /usr/bin/env python
# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Common command line options for mtbringup tools."""

from mtlib import CrOSRemote
from mtlib.util import Path, GitRepo, AskUser, Emerge
from argparse import ArgumentParser

src_dir = Path("/mnt/host/source/src/")

class MTBringupToolArgs(object):
  def __init__(self, args=None):
    self.device = None
    self.board = None
    self.remote = None
    self.verbose = None
    if args:
      self.device = args.device
      self.board = args.board
      self.remote = args.remote
      self.verbose = args.verbose

class MTBringupTool(object):
  def __init__(self, args):
    self.args = args
    self.verbose = args.verbose
    self.board_variant = None

    self._remote = None
    self._device_info = None

    if args.remote:
      self._remote = CrOSRemote(args.remote)
      self._device_info = self._remote.GetDeviceInfo()
      self.board_variant = self._device_info.board_variant
    if args.board:
      self.board_variant = args.board

    if not self.board_variant:
      raise Exception("Specify either --remote or --board")

    parts = self.board_variant.split("_")
    self.board = parts[0]
    self.variant = parts[1] if len(parts) > 1 else None

    self.branch_name = "{}_bringup".format(self.board_variant)
    self.emerge = Emerge(self.board_variant)

  @property
  def has_remote(self):
    return self._remote is not None

  @property
  def remote(self):
    if self._remote:
      return self._remote
    raise Exception("This operation requires --remote to be specified.")

  @property
  def device_info(self):
    if self._device_info:
      return self._device_info
    raise Exception("This operation requires --remote to be specified.")

  def FindDevice(self, device_match):
    for device in self.device_info.touch_devices.values():
      if device_match in device.id:
        return device
      if device_match in device.hw_name:
        return device
      if device_match in device.name:
        return device
    raise Exception("Cannot find device matching '{}'".format(device_match))

  def AskForDevice(self, question):
    if self.args.device:
      return self.FindDevice(self.args.device)
    devices = self.device_info.touch_devices
    if len(devices) == 1:
      return devices.values()[0]
    selection = AskUser.Select(devices.values(), question)
    return devices.values()[selection]

  def GitRepoPrepared(self, path):
    if not path.exists:
      path.MakeDirs()
    repo = GitRepo(path)
    if repo.active_branch != self.branch_name:
      raise Exception("Git repository is not prepared.")

  def PrepareGit(self, path):
    path.MakeDirs()
    repo = GitRepo(path)

    if not repo.path.exists:
      raise Exception("Cannot find git repo at {}".format(repo.path))

    if repo.active_branch == self.branch_name:
      return

    if repo.working_directory_dirty:
      print "There are local changes in {}".format(repo.path)
      if AskUser.YesNo("Would you like to stash the changes?", default=False):
        repo.Stash()
      elif AskUser.YesNo("Would you like to discard the changes?",
                         default=False):
        repo.Checkout("m/master", force=True)
      else:
        msg = "Cannot continue with local changes in {}"
        raise Exception(msg.format(repo.path))

    branch_name = self.branch_name
    if branch_name in repo.branches:
      print "Checking out {} in {}".format(branch_name, repo.path)
      repo.Checkout(branch_name)
    else:
      print "Creating branch {} in {}".format(branch_name, repo.path)
      repo.CreateBranch(branch_name, "m/master")

  def CleanGit(self, path):
    repo = GitRepo(path)
    if self.branch_name in repo.branches:
      print "Deleting branch {} in {}".format(self.branch_name, repo.path)
      repo.DeleteBranch(self.branch_name)

  def Upload(self, repo):
    review_url = repo.Upload()
    if not review_url:
      review_url = "Not uploaded. Change is up to date."
    print "Review URL:\n\t", review_url, "\n"

  def Status(self):
    pass

  def Prepare(self):
    pass

  def Verify(self):
    pass

  def Commit(self, bug_id):
    pass

  def Clean(self):
    pass


def MTBringupArgumentParser(usage):
  parser = ArgumentParser(usage=usage)
  parser.add_argument('-r', '--remote',
                      dest='remote', default=None,
                      help='remote ip address of chromebook')
  parser.add_argument('-b', '--board',
                      dest='board', default=None,
                      help='board name to use for process')
  parser.add_argument('-v', '--verbose',
                      dest='verbose', default=False, action="store_true",
                      help='show executed commands and their outputs')
  parser.add_argument('-d', '--device',
                      dest='device', default=None,
                      help='I2C device match to use for operations. Can be ' +
                           'part of device name, driver name or I2C id.')
  parser.add_argument('--bug',
                      dest='bug', default=None,
                      help='id of bug report tracking this device bringup.')
  return parser

def ExecuteCommonCommands(args, tool):
  if args.prepare:
    tool.Prepare()
  elif args.verify:
    tool.Verify()
  elif args.commit:
    bug = args.bug
    if not bug:
      bug = AskUser.Text("What is the bug id tracking this device bringup?")
    tool.Commit(bug)
  elif args.clean:
    tool.Clean()
  else:
    tool.Status()
